#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/udp.h>
#include <netinet/ip6.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define SOURCE_IP "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx"
#define SOURCE_PORT xxxx
#define DESTINATION_IP "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx"
#define DESTINATION_PORT xxxx
unsigned short get_ipv6_udp_checksum(unsigned short *addr, int len, struct in6_addr src_ip, struct in6_addr  dst_ip) {  
    register long sum = 0;  
    unsigned short answer;  
    unsigned short *w = addr;  
    unsigned short oddbyte;  
    unsigned short *src_ip_ptr = (unsigned short *)&src_ip;
    unsigned short *dst_ip_ptr = (unsigned short *)&dst_ip;
    for(int i = 0;i < 8;i++){
        sum += *(src_ip_ptr+i);
        sum += *(dst_ip_ptr+i);
    } 
    sum += htons(IPPROTO_UDP);
    sum += htons(len);
    while(len > 1) {  
        sum += *w++;  
        len -= 2;  
    }   
    if(len == 1) {  
        oddbyte = 0;  
        *((unsigned char*)&oddbyte) = *(unsigned char*)w;  
        sum += oddbyte;  
    }   
    sum = (sum >> 16) + (sum & 0xffff);  
    sum += (sum >> 16);  
    answer = ~sum;   
    return answer;  
}  
int main() {
    int sockfd;
    char buffer[4096]={0};
    char data[5]="hello";
    memset(buffer,0,sizeof(buffer));
    struct ip6_hdr *iph = (struct ip6_hdr *) buffer;
    struct udphdr *udph = (struct udphdr *) (buffer + sizeof(struct ip6_hdr));
    sockfd = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
    if (sockfd < 0) {
        perror("socket");
        exit(1);
    }
    memset(buffer, 0, sizeof(buffer));
    iph->ip6_flow = htonl((6 << 28) | (0 << 20) | 0);
    iph->ip6_plen = htons(sizeof(struct udphdr)+sizeof(data));
    iph->ip6_nxt = IPPROTO_UDP; 
    iph->ip6_hops = 255; 
    inet_pton(AF_INET6, SOURCE_IP, &(iph->ip6_src));
    inet_pton(AF_INET6, DESTINATION_IP, &(iph->ip6_dst));
    udph->source = htons(SOURCE_PORT);
    udph->dest = htons(DESTINATION_PORT);
    udph->len = htons(sizeof(struct udphdr)+sizeof(data));
    memcpy((void*)(buffer + sizeof(struct ip6_hdr) + sizeof(struct udphdr)), (void*)data, sizeof(data));
    udph->check = get_ipv6_udp_checksum((unsigned short *)udph,sizeof(struct udphdr) + sizeof(data),iph->ip6_src,iph->ip6_dst);
    struct sockaddr_in6 dest_addr;
    memset(&dest_addr, 0, sizeof(dest_addr));
    dest_addr.sin6_family = AF_INET6;
    inet_pton(AF_INET6, DESTINATION_IP, &dest_addr.sin6_addr);
    if (sendto(sockfd, buffer, sizeof(struct ip6_hdr)+sizeof(struct udphdr)+sizeof(data), 0, (struct sockaddr *) &dest_addr, sizeof(dest_addr)) < 0) {
        perror("sendto");
        exit(1);
    }
    close(sockfd);
    return 0;
}